/*
 * funcionesFAT32.c
 *
 *  Created on: 03/11/2011
 *      Author: utn_so
 */

#include "funcionesFAT32.h"

extern struct bootSector* bootSectorDisco;
extern int32_t cacheActiva;
//	Operaciones criticas
extern pthread_mutex_t mutex_fat;

char* bufferLog;
char* aux_str;

//	log de numeros
void itoaFunc(int32_t , char []);
void reverseFunc(char []);


/*	Crear Archivo	*/

/*int32_t pfs_create(const char *path, mode_t mode, struct fuse_file_info *fi)*/

int32_t crearArchivo(const char* path)
{

	ListaDirectorios* directorioFound = malloc(sizeof(ListaDirectorios));
	char* pathAux = malloc (sizeof(char)*30);
	char* pathSinArchivo = malloc (sizeof(char)*30);
	char* pathAuxAnt;
	char* pathAuxAnt2;
	char* nombreArchivo;

	strcpy(pathSinArchivo,"NoHayPATH");
	strcpy(pathAux, path);

	char tokens[2] = "/";
	pathAuxAnt = strtok(pathAux, tokens);
	pathAuxAnt2 = pathAuxAnt;

	while(pathAuxAnt != NULL)
		{
		nombreArchivo = pathAuxAnt;
		pathAuxAnt = strtok(NULL, tokens);

		if(pathAuxAnt!=NULL)
			{
			if(strcmp(pathSinArchivo,"NoHayPATH") == 0)
				strcpy(pathSinArchivo,pathAuxAnt2);
			else
				strcat(pathSinArchivo,pathAuxAnt2);
			strcat(pathSinArchivo, "/");
			pathAuxAnt2 = pathAuxAnt;
			}
		}

	if(strcmp(pathSinArchivo,"NoHayPATH") == 0)
		strcpy(pathSinArchivo, "./");

	/*printf("Path sin archivo: %s\n", pathSinArchivo);
	printf("Nombre del archivo: %s\n", nombreArchivo);*/

	directorioFound -> clusters = NULL;
	directorioFound -> directorio = NULL;
	directorioFound -> nombreLargo = NULL;
	directorioFound -> siguiente = NULL;
	int32_t res = verificarPath(bootSectorDisco, pathSinArchivo, directorioFound);
	/*	en directorioFound tengo la info del directorio padre, si es el root
	 * 	no tengo nada	*/

	if(res == -1)
		{
		/*	entrada incorrecta	*/
		liberarDirectorio(directorioFound);
		bufferLog = malloc(sizeof(char)*100);
		strcpy(bufferLog, path);
		strcat(bufferLog, ", entrada incorrecta, path invalido");
		escribir_logfile(NOMPS, 0, ERROR, bufferLog);
		free(bufferLog);
		free(pathAux);
		free(pathSinArchivo);
		return -1;
		}

	uint32_t clusterEnt;
	if(directorioFound -> directorio != NULL)
		clusterEnt = proximaEntryDir(directorioFound -> directorio);

	else
		clusterEnt = bootSectorDisco -> BPB_RootClus;

	liberarDirectorio(directorioFound);

	/*	Antes de crear algo debo verificar que no exista una
	 * 	entrada con el mismo nombre								*/

	ListaDirectorios* firstDir = malloc(sizeof(ListaDirectorios));
	firstDir -> directorio = NULL;
	firstDir -> siguiente = NULL;
	firstDir -> clusters = NULL;
	firstDir -> nombreLargo = NULL;
	ListaDirectorios* lastDir = NULL;
	leerFAT32DirectoryEntries( bootSectorDisco, clusterEnt, firstDir, lastDir);

	//	va liberando memoria
	if(verificarNombreDistinto(firstDir, nombreArchivo) == -1)
		{
		/*	hay un archivo con el mismo nombre	*/
		bufferLog = malloc(sizeof(char)*200);
		strcpy(bufferLog, path);
		strcat(bufferLog, ", ya existe otro archivo con ese nombre");
		escribir_logfile(NOMPS, 0, ERROR, bufferLog);
		free(bufferLog);
		free(pathAux);
		free(pathSinArchivo);
		return -1;
		}

	struct DirStruct* dir = malloc(sizeof(struct DirStruct));
	struct LongDirStruct* lfn = malloc(sizeof(struct LongDirStruct));

	if (crearEntradaDIR(bootSectorDisco, nombreArchivo, dir, ARCHIVO) == -1)
		return -1;

	if (crearEntradaLFN(nombreArchivo, dir, lfn) == -1)
		return -1;

	if(crearEntradaCluster(bootSectorDisco, clusterEnt, dir, lfn) == -1)
		{
		/*	no se pudo crear archivo, espacio lleno	*/
		bufferLog = malloc(sizeof(char)*200);
		strcpy(bufferLog, path);
		strcat(bufferLog, ", no se pudo crear el archivo, espacio lleno");
		escribir_logfile(NOMPS, 0, ERROR, bufferLog);
		free(bufferLog);
		free(pathAux);
		free(pathSinArchivo);
		free(dir);
		free(lfn);
		return -1;
		}

	/*	LOG, archivo creado	*/
	bufferLog = malloc(sizeof(char)*100);
	strcpy(bufferLog, path);
	strcat(bufferLog, ", archivo creado");
	escribir_logfile(NOMPS, 0, INFO, bufferLog);
	free(bufferLog);

	free(pathAux);
	free(pathSinArchivo);
	free(dir);
	free(lfn);
	return 0;
}

/*	Abrir Archivo	*/

/*int32_t pfs_open(const char *path, struct fuse_file_info *fi)*/

ListaDirectorios* abrirArchivo(const char* path)
{
	/*	Archivo / Directorio	*/

	/*	busco en cache primero	*/
	ListaDirectorios* dir = NULL;

	if(cacheActiva)
		dir = buscarArchivoCache(path);

	/*	No esta en la cache	*/
	if(dir == NULL)
		{

		if(cacheActiva)
			dir = buscarCacheDirectorio(path);

		if(dir == NULL)
			{
			ListaDirectorios* directorioFound = malloc(sizeof(ListaDirectorios));
			directorioFound -> clusters = NULL;
			directorioFound -> nombreLargo = NULL;
			directorioFound -> directorio = NULL;
			directorioFound -> siguiente = NULL;
			int32_t res = verificarPath(bootSectorDisco, path, directorioFound);

			if(res == -1)
				{
				liberarDirectorio(directorioFound);
				bufferLog=malloc(sizeof(char)*200);
				strcpy(bufferLog,path);
				strcat(bufferLog, ", entrada incorrecta, path invalido");
				escribir_logfile(NOMPS, 0, ERROR, bufferLog);
				free(bufferLog);
				return NULL;
				}

			/*	root directory	*/
			if(res == 2 && (directorioFound -> directorio == NULL))
				{
				/*	Cuando se pregunta por el root directory, ej: "./"  "../"	*/
				unsigned char* bufferClus = malloc(sizeof(char)*4);
				ponerHexaEnBuffer(swap_uint32(2), bufferClus);

				struct DirStruct* dir = malloc(sizeof(struct DirStruct));
				directorioFound -> directorio = dir;

				/*	manganeta	*/
				directorioFound -> directorio -> DIR_FstClusHI[0] = bufferClus[2];
				directorioFound -> directorio -> DIR_FstClusHI[1] = bufferClus[3];
				directorioFound -> directorio -> DIR_FstClusLO[0] = bufferClus[0];
				directorioFound -> directorio -> DIR_FstClusLO[1] = bufferClus[1];
				free(bufferClus);
				}

			/*bufferLog=malloc(sizeof(char)*200);
			strcpy(bufferLog,path);
			strcat(bufferLog, ", archivo/directorio abierto s/cache");
			escribir_logfile(NOMPS, 0, INFO, bufferLog);
			free(bufferLog);*/

			if(cacheActiva)
				{
				if((directorioFound -> directorio -> DIR_Attr & ATTR_ARCHIVE)== ATTR_ARCHIVE
						&& (strcmp("/", path)!=0) )
					{addCacheFile(path, directorioFound); return buscarArchivoCache(path);}

				else
					{agregarCacheDirectorio(path, directorioFound);return buscarCacheDirectorio(path);}
				}
			else
				return directorioFound;

			}

		/*bufferLog=malloc(sizeof(char)*200);
		strcpy(bufferLog,path);
		strcat(bufferLog, ", directorio abierto c/cache");
		escribir_logfile(NOMPS, 0, INFO, bufferLog);
		free(bufferLog);*/
		return dir;

		}

	else
		{
		/*bufferLog=malloc(sizeof(char)*200);
		strcpy(bufferLog,path);
		strcat(bufferLog, ", archivo abierto c/cache");
		escribir_logfile(NOMPS, 0, INFO, bufferLog);
		free(bufferLog);*/
		return dir;
		}

	return NULL;

}

/*	Leer un Archivo	*/

/*int32_t pfs_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi)*/

int32_t leerArchivo(const char *path, char* buffer, size_t size, off_t offset)
{

	ListaDirectorios* dir = abrirArchivo(path);

	if(dir == NULL)
		//	log dentro de abrir archivo
		return -1;

	//	no hay nada para leer
	if(offset >= dir -> directorio -> DIR_FileSize )
		return 0;

	int32_t bytesClusters = bootSectorDisco -> BPB_BytsPerSec * bootSectorDisco -> BPB_SecPerClus;

	//	segun el offset calculo el cluster que tengo que pedir
	uint32_t numCluster = dameClusterSegunOffset(bootSectorDisco, offset);

	//	lista de clusters
	crearCadenaCluster(bootSectorDisco, dir);

	// el tope depende del cluster
	int32_t tope = (bytesClusters * dir -> clusters[numCluster]) + bytesClusters - 1;

	//	el comienzo si/no
	int32_t comienzo_0 = offset -
			(numCluster * bootSectorDisco -> BPB_BytsPerSec * bootSectorDisco -> BPB_SecPerClus);

	int32_t comienzo_cluster = comienzo_0 +
			(dir -> clusters[numCluster] * bytesClusters);

	uint32_t sectorIni = firstSectorofCluster(bootSectorDisco, dir -> clusters[numCluster]);

	unsigned char* buffCluster = malloc(sizeof(char)* bootSectorDisco->BPB_BytsPerSec * bootSectorDisco->BPB_SecPerClus);
	//	 Verifico si esta en cache
	if(cacheActiva)
		{
		if(searchCacheData(path, dir -> clusters[numCluster], buffCluster) == -1)
			{
			buffCluster = traerCluster(bootSectorDisco, sectorIni);
			addCacheData(path, dir -> clusters[numCluster] ,buffCluster, LECTURA, sectorIni);
			}
		}

	else
		buffCluster = traerCluster(bootSectorDisco, sectorIni);

	int32_t dentroCluster = comienzo_cluster;
	int32_t i = comienzo_0;
	int32_t recorrido;
	int32_t cantPasada;

	//	tengo que ver cuanto tengo que leer
	 uint32_t sizeArchivo = dir -> directorio -> DIR_FileSize;

	 if(sizeArchivo < (offset + size))  //Si me paso del tamaño del archivo leyendo una cantidad size desde offset
		 cantPasada = sizeArchivo - offset; //Leo lo que quedaba del archivo (5000-4096 = 904)
	 else
		 cantPasada = size; //En otro caso leo el tamaño que pidió

	for(recorrido = 0; recorrido < cantPasada; recorrido++)
		{
		// se acabo el cluster, pido otro
		if(dentroCluster > tope)
			{
			//se supone que voy a tener mas clusters disponibles
			numCluster++;
			sectorIni = firstSectorofCluster(bootSectorDisco, dir -> clusters[numCluster]);
			//verifico primero que este en cache
			if(cacheActiva)
				{
				if(searchCacheData(path, dir -> clusters[numCluster], buffCluster) == -1)
					{
					buffCluster = traerCluster(bootSectorDisco, sectorIni);
					addCacheData(path, dir -> clusters[numCluster] ,buffCluster, LECTURA, sectorIni);
					}
				}
			else
				buffCluster = traerCluster(bootSectorDisco, sectorIni);

			dentroCluster = (dir -> clusters[numCluster] * bytesClusters);
			tope = (bytesClusters * dir -> clusters[numCluster]) + bytesClusters -1;
			i=0;
			}

		buffer[recorrido] = buffCluster[i];
		dentroCluster++;
		i++;
		}

	free(dir -> clusters);
//CACA	free(buffCluster);

	if(!cacheActiva)
		liberarDirectorio(dir);

	//	log
	/*bufferLog = malloc(sizeof(char)*100);
	aux_str = malloc(sizeof(char)*20);
	strcpy(bufferLog, path);
	strcat(bufferLog, ", se leyeron ");
	itoaFunc(cantPasada, aux_str);
	strcat(buffer, aux_str);
	strcat(buffer, " bytes");
	escribir_logfile(NOMPS, 0, INFO, bufferLog);
	free(aux_str);
	free(bufferLog);*/

	return cantPasada;

}

/*	Escribir un archivo	*/

/*int32_t pfs_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi)*/

int32_t escribirArchivo(const char *path, const char *buffer, size_t size, off_t offset)
{

	ListaDirectorios* dir = abrirArchivo(path);

	if(dir == NULL)
		// log dentro de abrir archivo
		return -1;

	//	si el archivo no tiene cluster asignado
	if(dir -> directorio -> DIR_FileSize == 0)
		{
		truncarArchivo(path, size);
		//	lo tengo que volver a abrir, cambio dir
		dir = abrirArchivo(path);
		//	no deberia pasar
		if(dir == NULL)
			return -1;
		}

	//	tengo un offset mayor al tamaño del archivo
	else if(offset >= dir -> directorio -> DIR_FileSize)
		{
		// reasigno el tamaño del archivo
		truncarArchivo(path, (dir -> directorio -> DIR_FileSize + size));
		//	lo tengo que volver a abrir, cambio dir
		dir = abrirArchivo(path);
		//	no deberia pasar
		if(dir == NULL)
			return -1;
		}

	int32_t bytesClusters = bootSectorDisco -> BPB_BytsPerSec * bootSectorDisco -> BPB_SecPerClus;

	//	segun el offset calculo el cluster que tengo que pedir
	uint32_t numCluster = dameClusterSegunOffset(bootSectorDisco, offset);

	//	lista de clusters
	crearCadenaCluster(bootSectorDisco, dir);

	// el tope depende del cluster
	int32_t tope = (bytesClusters * dir -> clusters[numCluster]) + bytesClusters - 1;

	//	el comienzo si/no
	int32_t comienzo_0 = offset -
			(numCluster * bootSectorDisco -> BPB_BytsPerSec * bootSectorDisco -> BPB_SecPerClus);

	int32_t comienzo_cluster = comienzo_0 +
			(dir -> clusters[numCluster] * bytesClusters);

	uint32_t sectorIni = firstSectorofCluster(bootSectorDisco, dir -> clusters[numCluster]);

	unsigned char* buffCluster = malloc(sizeof(char)* bootSectorDisco->BPB_BytsPerSec * bootSectorDisco->BPB_SecPerClus);

	// si es igual al tamaño del cluster lo persiste de una, no lo trae
	if(size==bytesClusters)
		{
		//	meto en cache si esta habilitada
		//	persisto el cluster modificado
		if(cacheActiva)
			addCacheData(path, dir -> clusters[numCluster] ,buffer, ESCRITURA, sectorIni);
		else
			persistirCluster(bootSectorDisco, dir -> clusters[numCluster], buffer);
		}

	else
	{
	//	verifico si no esta en la cache primero
	if(cacheActiva)
		{
		if(searchCacheData(path, dir -> clusters[numCluster], buffCluster) == -1)
			{
			buffCluster = traerCluster(bootSectorDisco, sectorIni);
			addCacheData(path, dir -> clusters[numCluster] ,buffCluster, LECTURA, sectorIni);
			}
		}

	else
		buffCluster = traerCluster(bootSectorDisco, sectorIni);

	int32_t dentroCluster = comienzo_cluster;
	int32_t i = comienzo_0;
	int32_t recorrido;

	for(recorrido = 0; recorrido <size; recorrido++)
		{
		// se acabo el cluster
		if(dentroCluster > tope)
			{
			//	meto en cache si esta habilitada
			//	persisto el cluster modificado
			if(cacheActiva)
				addCacheData(path, dir -> clusters[numCluster] ,buffCluster, ESCRITURA, sectorIni);

			else
				persistirCluster(bootSectorDisco, dir -> clusters[numCluster], buffCluster);

			numCluster++;

			if(cacheActiva)
				{
				if(searchCacheData(path, dir -> clusters[numCluster], buffCluster) == -1)
					{
					buffCluster = traerCluster(bootSectorDisco, sectorIni);
					addCacheData(path, dir -> clusters[numCluster] ,buffCluster, LECTURA, sectorIni);
					}
				}

			else
				buffCluster = traerCluster(bootSectorDisco, sectorIni);

			i=0;
			}

		buffCluster[i] = buffer[recorrido];
		dentroCluster++;
		i++;
		}

	//llenar con ceros
	if(dentroCluster<tope)
		{
		//arrastro el valor de i
		for(; i<bytesClusters; i++)
			buffCluster[i] = 0x00;
		}

	//	meto en cache si esta habilitada
	//	persisto el cluster modificado
	if(cacheActiva)
		addCacheData(path, dir -> clusters[numCluster] ,buffCluster, ESCRITURA, sectorIni);
	else
		persistirCluster(bootSectorDisco, dir -> clusters[numCluster], buffCluster);
	}

	//	log
	/*bufferLog = malloc(sizeof(char)*100);
	aux_str = malloc(sizeof(char)*20);
	strcpy(bufferLog, path);
	strcat(bufferLog, ", se escribio ");
	itoaFunc(size, aux_str);
	strcat(bufferLog, aux_str);
	strcat(bufferLog, " bytes");
	escribir_logfile(NOMPS, 0, INFO, bufferLog);
	free(aux_str);
	free(bufferLog);*/

	free(dir->clusters);
//CACA	free(buffCluster);
	return size;

}

/*	Borrar un archivo	*/

/*	int32_t pfs_unlink(const char *path)	*/

int32_t borrarArchivo(const char* path)
{

	ListaDirectorios* directorioFound = abrirArchivo(path);

	if(directorioFound == NULL)
		//	log dentro de abrir archivo
		return -1;

	/*	limpio los sectores en la fat	*/
	/*	los archivos recien creados se les pone cluster siguiente = 0*/

	//	lista de clusters
	crearCadenaCluster(bootSectorDisco, directorioFound);
	int32_t i = 0;
	while(1)
		{
		if(directorioFound -> clusters[i] != SIGNAL_NO_MORE)
			{
			pthread_mutex_lock(&mutex_fat);
			cambiarEntradaFAT(bootSectorDisco, directorioFound -> clusters[i], 0);
			pthread_mutex_unlock(&mutex_fat);
			i++;
			}
		else
			break;
		}

	free(directorioFound->clusters);
	/*	busca la entrada y la pongo como vacia	*/
	borrarEntradaCluster(bootSectorDisco, directorioFound);

	/*	NO borro entrada cache, despues el kernel me tira un realese	*/
	if(cacheActiva)
		deleteCacheFileNoFlush(path);
	else
		liberarDirectorio(directorioFound);

	//	log
	bufferLog = malloc(sizeof(char)*100);
	strcpy(bufferLog, path);
	strcat(bufferLog, ", archivo borrado");
	escribir_logfile(NOMPS, 0, INFO, bufferLog);
	free(bufferLog);

	return 0;
}

/*	Truncar un archivo	*/

/*	int32_t pfs_truncate(const char *path, off_t newsize)	*/

int32_t truncarArchivo(const char* path, int32_t newSize)
{

	ListaDirectorios* dir = abrirArchivo(path);

	if(dir == NULL)
		// log en abrir archivo
		return -1;

	 /* 	se borra la entrada, se hace automaticamente un flush
	  * 	se genera una nueva entrada a la cache, de ultima se persisten clusters modificados al pedo 	*/
	if(cacheActiva)
		dir = deleteCacheFileFlushTruncate(path);

	if(dir == NULL)
		// no deberia pasar
		return -1;

	int32_t numClustersNes = cantidadClusterSegunTamanio(bootSectorDisco, newSize);

	int32_t numActClusters = cantidadClusterActualDir(bootSectorDisco, dir);

	int32_t *listaNueva = malloc(sizeof(int32_t) * numClustersNes);
	int32_t i, ant, prox;
	int32_t clusterPasaje;
	int32_t comienzo;
	//mas facil con la cadena de cluster armada
	crearCadenaCluster(bootSectorDisco, dir);
	if(numClustersNes > numActClusters)
		{
		int32_t clustersAgregados = numClustersNes - numActClusters;

		//	copia de la lista vieja
		for(i=0; i < numActClusters; i++)
			listaNueva[i] = dir -> clusters[i];

		comienzo = numActClusters;

		for(i=0; i<clustersAgregados; i++)
			{
			//	no tengo ningun clusters asignado al archivo
			//	solo lo hace la primera vez
			if(numActClusters == 0 && i == 0)
				{
				prox = dameClusterLibre(bootSectorDisco);
				listaNueva[0] = prox;
				}

			else
				{
				prox = dameClusterLibre(bootSectorDisco);
				listaNueva[comienzo + i] = prox;
				ant = comienzo + i - 1;
				clusterPasaje = listaNueva[ant];
				pthread_mutex_lock(&mutex_fat);
				cambiarEntradaFAT(bootSectorDisco, clusterPasaje, prox);
				pthread_mutex_unlock(&mutex_fat);
				}
			}

		/*	EOC	*/
		pthread_mutex_lock(&mutex_fat);
		cambiarEntradaFAT(bootSectorDisco, prox, 0x0FFFFFFF);
		pthread_mutex_unlock(&mutex_fat);

		/*	el archivo no tenia ningun cluster asignado	*/
		if(numActClusters == 0)
			{
			unsigned char* bufferClus = malloc(sizeof(char)*4);
			ponerHexaEnBuffer(swap_uint32(listaNueva[0]), bufferClus);

			/*	manganeta	*/
			dir -> directorio -> DIR_FstClusHI[0] = bufferClus[2];
			dir -> directorio -> DIR_FstClusHI[1] = bufferClus[3];
			dir -> directorio -> DIR_FstClusLO[0] = bufferClus[0];
			dir -> directorio -> DIR_FstClusLO[1] = bufferClus[1];
			free(bufferClus);
			}
		}

	/*	es menor	*/
	else
		{
		int32_t clustersSacados = numActClusters - numClustersNes;
		int32_t atrasAdelante = numActClusters - 1;

		/*	saco clusters	*/
		for(i=0; i < clustersSacados; i++)
			{
			pthread_mutex_lock(&mutex_fat);
			cambiarEntradaFAT(bootSectorDisco, dir -> clusters[atrasAdelante-i], 0x00);
			pthread_mutex_unlock(&mutex_fat);
			}

		if(clustersSacados == numActClusters)
			{
			//truncate 0
			dir -> directorio -> DIR_FstClusHI[0] = 0x00;
			dir -> directorio -> DIR_FstClusHI[1] = 0x00;
			dir -> directorio -> DIR_FstClusLO[0] = 0x00;
			dir -> directorio -> DIR_FstClusLO[1] = 0x00;
			}

		//	marco el ultimo cluster que me quedo como EOC
		else
			{
			pthread_mutex_lock(&mutex_fat);
																/*	posicion en el vector	*/
			cambiarEntradaFAT(bootSectorDisco, dir -> clusters[(numActClusters - clustersSacados)-1], 0x0FFFFFFF);
			pthread_mutex_unlock(&mutex_fat);
			}
		}

	/*	cambiar tamaño en dir	*/
	int32_t nuevoTam = swap_uint32(newSize);
	unsigned char* bufferAux = malloc(sizeof(char)*4);
	ponerHexaEnBuffer(nuevoTam, bufferAux);

	/*	nuevo tamaño	*/
	dir -> directorio -> DIR_FileSizePOSTA[0] = bufferAux[0];
	dir -> directorio -> DIR_FileSizePOSTA[1] = bufferAux[1];
	dir -> directorio -> DIR_FileSizePOSTA[2] = bufferAux[2];
	dir -> directorio -> DIR_FileSizePOSTA[3] = bufferAux[3];

	dir ->directorio ->DIR_FileSize = newSize;

	free(bufferAux);
	modificarDir(bootSectorDisco, dir, NULL);

	free(dir->clusters);

	//	dir cambio, genero una nueva entrada a la cache
	if(!cacheActiva)
		liberarDirectorio(dir);

	free(listaNueva);

	//	log
	/*bufferLog = malloc(sizeof(char)*100);
	aux_str = malloc(sizeof(char)*20);
	strcpy(bufferLog, path);
	strcat(bufferLog, ", archivo truncado a ");
	itoaFunc(newSize, aux_str);
	strcat(bufferLog, aux_str);
	strcat(buffer, " bytes");
	escribir_logfile(NOMPS, 0, INFO, bufferLog);
	free(aux_str);
	free(bufferLog);*/

	return 0;

}

/*	Crear un directorio	*/

/*	int32_t pfs_mkdir(const char *path, mode_t mode)	*/

int32_t crearCarpeta(const char *path)
{
	/*	muy similar a archivo, cero ganas de optimizar	*/

	ListaDirectorios* directorioFound = malloc(sizeof(ListaDirectorios));
	char* pathAux = malloc (sizeof(char)*30);
	char* pathSinArchivo = malloc (sizeof(char)*30);
	char* pathAuxAnt;
	char* pathAuxAnt2;
	char* nombreArchivo;

	strcpy(pathSinArchivo,"NoHayPATH");
	strcpy(pathAux, path);

	char tokens[2] = "/";
	pathAuxAnt = strtok(pathAux, tokens);
	pathAuxAnt2 = pathAuxAnt;

	while(pathAuxAnt != NULL)
		{
		nombreArchivo = pathAuxAnt;
		pathAuxAnt = strtok(NULL, tokens);

		if(pathAuxAnt!=NULL)
			{
			if(strcmp(pathSinArchivo,"NoHayPATH") == 0)
				strcpy(pathSinArchivo,pathAuxAnt2);
			else
				strcat(pathSinArchivo,pathAuxAnt2);
			strcat(pathSinArchivo, "/");
			pathAuxAnt2 = pathAuxAnt;
			}
		}

	if(strcmp(pathSinArchivo,"NoHayPATH") == 0)
		strcpy(pathSinArchivo, "./");

	/*printf("Path sin archivo: %s\n", pathSinArchivo);
	printf("Nombre del archivo: %s\n", nombreArchivo);*/

	directorioFound -> clusters = NULL;
	directorioFound -> directorio = NULL;
	directorioFound -> nombreLargo = NULL;
	directorioFound -> siguiente = NULL;
	int32_t res = verificarPath(bootSectorDisco, pathSinArchivo, directorioFound);
	/*	en directorioFound tengo la info del directorio padre, si es el root
	 * 	no tengo nada	*/

	if(res == -1)
		{
		/*	entrada incorrecta	*/
		liberarDirectorio(directorioFound);
		bufferLog = malloc(sizeof(char)*100);
		strcpy(bufferLog, path);
		strcat(bufferLog, ", entrada incorrecta, path invalido");
		escribir_logfile(NOMPS, 0, ERROR, bufferLog);
		free(bufferLog);
		free(pathAux);
		free(pathSinArchivo);
		return -1;
		}

	uint32_t clusterEnt;
	if(directorioFound -> directorio != NULL)
		clusterEnt = proximaEntryDir(directorioFound -> directorio);
	else
		clusterEnt = bootSectorDisco -> BPB_RootClus;

	liberarDirectorio(directorioFound);

	/*	Antes de crear algo debo verificar que no exista una
	 * 	entrada con el mismo nombre								*/
	ListaDirectorios* firstDir = malloc(sizeof(ListaDirectorios));
	firstDir -> directorio = NULL;
	firstDir -> siguiente = NULL;
	firstDir -> clusters = NULL;
	firstDir -> nombreLargo = NULL;
	ListaDirectorios* lastDir = NULL;
	leerFAT32DirectoryEntries( bootSectorDisco, clusterEnt, firstDir, lastDir);

	//	va liberando memoria
	if(verificarNombreDistinto(firstDir, nombreArchivo) == -1)
		{
		/*	hay un archivo con el mismo nombre	*/
		bufferLog = malloc(sizeof(char)*200);
		strcpy(bufferLog, path);
		strcat(bufferLog, ", ya existe otra carpeta con ese nombre");
		escribir_logfile(NOMPS, 0, ERROR, bufferLog);
		free(bufferLog);
		free(pathAux);
		free(pathSinArchivo);
		return -1;
		}

	struct DirStruct* dir = malloc(sizeof(struct DirStruct));
	struct LongDirStruct* lfn = malloc(sizeof(struct LongDirStruct));

	if( crearEntradaDIR(bootSectorDisco, nombreArchivo, dir, DIRECTORIO) == -1)
		return -1;

	if (crearEntradaLFN(nombreArchivo, dir, lfn) == -1)
		return -1;

	/*	asignar cluster del directorio	*/
	int32_t clusterDir = dameClusterLibre(bootSectorDisco);

	//	no hay cluster libres
	if(clusterDir == -1)
		{
		bufferLog = malloc(sizeof(char)*200);
		strcpy(bufferLog, path);
		strcat(bufferLog, ", no hay cluster libre para asignar al directorio");
		escribir_logfile(NOMPS, 0, ERROR, bufferLog);
		free(bufferLog);
		free(dir);
		free(lfn);
		free(pathAux);
		free(pathSinArchivo);
		return -1;
		}

	/*	seteo en la fat como ultimo cluster	*/
	pthread_mutex_lock(&mutex_fat);
	cambiarEntradaFAT(bootSectorDisco, clusterDir, 0x0FFFFFFF);
	pthread_mutex_unlock(&mutex_fat);
	unsigned char* bufferClus = malloc(sizeof(char)*4);
	ponerHexaEnBuffer(swap_uint32(clusterDir), bufferClus);

	/*	manganeta	*/
	dir -> DIR_FstClusHI[0] = bufferClus[2];
	dir -> DIR_FstClusHI[1] = bufferClus[3];
	dir -> DIR_FstClusLO[0] = bufferClus[0];
	dir -> DIR_FstClusLO[1] = bufferClus[1];
	free(bufferClus);

	if(crearEntradaCluster(bootSectorDisco, clusterEnt, dir, lfn) == -1)
		{
		/*	log, no se pudo crear archivo, espacio lleno	*/
		bufferLog = malloc(sizeof(char)*200);
		strcpy(bufferLog, path);
		strcat(bufferLog, ", no se pudo crear el directorio, espacio lleno");
		escribir_logfile(NOMPS, 0, ERROR, bufferLog);
		free(bufferLog);

		// vuelvo para atras el cluster pedido
		pthread_mutex_lock(&mutex_fat);
		cambiarEntradaFAT(bootSectorDisco, clusterDir, 0x00);
		pthread_mutex_unlock(&mutex_fat);

		free(dir);
		free(lfn);
		free(pathAux);
		free(pathSinArchivo);
		return -1;
		}

	crearEntradaDOT_DOTDOT(bootSectorDisco, clusterDir, clusterEnt);

	//	persistir fat
	persistirFAT(bootSectorDisco);

	//	LOG, directorio creado
	bufferLog = malloc(sizeof(char)*200);
	strcpy(bufferLog, path);
	strcat(bufferLog, ", directorio creado");
	escribir_logfile(NOMPS, 0, INFO, bufferLog);
	free(bufferLog);

	free(dir);
	free(lfn);
	free(pathAux);
	free(pathSinArchivo);
	return 0;

}

/*	Leer un directorio	*/

/*	int32_t pfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi);*/

int32_t lsdir(const char *path, ListaDirectorios* firstDir)
{

	ListaDirectorios* dir = abrirArchivo(path);

	if(dir == NULL)
		{
		/*	LOG	*/
		return -1;
		}

	firstDir -> directorio = NULL;
	firstDir -> siguiente = NULL;
	firstDir -> clusters = NULL;
	firstDir -> nombreLargo = NULL;
	ListaDirectorios* lastDir = NULL;

	leerFAT32DirectoryEntries(bootSectorDisco, proximaEntryDir(dir -> directorio), firstDir, lastDir);

	//	lo tengo que borrar si no esta activa la cache
	if(!cacheActiva)
		liberarDirectorio(dir);

	/*	LOG	*/

	return 0;

}

/*	Borrar un directorio	*/

/*	int32_t pfs_rmdir(const char *path);	*/

int32_t borrarCarpeta(const char *path)
{

	ListaDirectorios* dir = abrirArchivo(path);

	if(dir == NULL)
		{
		/*	LOG	*/
		return -1;
		}

	//	SOLO SI LA CARPETA TIENE DOS ENTRADAS . Y ..

	ListaDirectorios* firstDir = malloc(sizeof(ListaDirectorios));
	firstDir -> directorio = NULL;
	firstDir -> siguiente = NULL;
	firstDir -> clusters = NULL;
	firstDir -> nombreLargo = NULL;
	ListaDirectorios* lastDir = NULL;

	leerFAT32DirectoryEntries(bootSectorDisco, proximaEntryDir(dir -> directorio), firstDir, lastDir);

	int32_t cantidadDeDir = 0;
	ListaDirectorios* pasaje;
	// siempre va a tener dos entradas, minimo
	do
		{
		pasaje = (ListaDirectorios*) firstDir -> siguiente;
		liberarDirectorio(firstDir);
		firstDir = pasaje;

		cantidadDeDir++;

		/*if(firstDir -> siguiente == NULL)
			break;*/
		}while(firstDir!= NULL);

	/*	Solo . Y ..*/
	if(cantidadDeDir == 2)
		{
		pthread_mutex_lock(&mutex_fat);
		cambiarEntradaFAT(bootSectorDisco, proximaEntryDir(dir -> directorio), 0);
		pthread_mutex_unlock(&mutex_fat);

		/*	Limpio el cluster del directorio	*/
		borrarEntradaClusterDIR(bootSectorDisco, dir);

		/*	limpio la entrada del directotio padre	*/
		borrarEntradaCluster(bootSectorDisco, dir);

		//	persistir fat
		persistirFAT(bootSectorDisco);

		liberarDirectorio(dir);

		//	log
		bufferLog = malloc(sizeof(char)*100);
		strcpy(bufferLog, path);
		strcat(bufferLog, ", directorio borrado");
		escribir_logfile(NOMPS, 0, INFO, bufferLog);
		free(bufferLog);

		return 0;
		}

	liberarDirectorio(dir);
	bufferLog = malloc(sizeof(char)*100);
	strcpy(bufferLog, path);
	strcat(bufferLog, ", Carpeta con contenido, no se puede borrar");
	escribir_logfile(NOMPS, 0, ERROR, bufferLog);
	free(bufferLog);

	return -1;
}

/*	Renombrar un archivo/directorio	*/

/*	int32_t pfs_rename(const char *path, const char *newpath);	*/

int32_t renombrar(const char *path, const char *newpath)
{

	ListaDirectorios* dirOriginal = abrirArchivo(path);

	if(dirOriginal == NULL)
		return -1;

	char* pathAux = malloc (sizeof(char)*30);
	char* pathSinArchivo = malloc (sizeof(char)*30);
	char* pathAuxAnt;
	char* pathAuxAnt2;
	char* nombreArchivoNuevo;

	strcpy(pathSinArchivo,"NoHayPATH");
	strcpy(pathAux, newpath);

	char tokens[2] = "/";
	pathAuxAnt = strtok(pathAux, tokens);
	pathAuxAnt2 = pathAuxAnt;

	while(pathAuxAnt != NULL)
		{
		nombreArchivoNuevo = pathAuxAnt;
		pathAuxAnt = strtok(NULL, tokens);

		if(pathAuxAnt!=NULL)
			{
			if(strcmp(pathSinArchivo,"NoHayPATH") == 0)
				strcpy(pathSinArchivo,pathAuxAnt2);
			else
				strcat(pathSinArchivo,pathAuxAnt2);
			strcat(pathSinArchivo, "/");
			pathAuxAnt2 = pathAuxAnt;
			}
		}

	if(strcmp(pathSinArchivo,"NoHayPATH") == 0)
		strcpy(pathSinArchivo, "./");

	printf("Path sin archivo: %s\n", pathSinArchivo);
	printf("Nombre del archivo: %s\n", nombreArchivoNuevo);

	ListaDirectorios* dirParentNuevo = malloc(sizeof(ListaDirectorios));
	dirParentNuevo -> clusters = NULL;
	dirParentNuevo -> directorio = NULL;
	dirParentNuevo -> nombreLargo = NULL;
	dirParentNuevo -> siguiente = NULL;
	int32_t res = verificarPath(bootSectorDisco, pathSinArchivo, dirParentNuevo);
	/*	en dirNuevo tengo la info del directorio padre, si es el root
	 * 	no tengo nada	*/

	if(res == -1)
		/*	entrada incorrecta	*/
		return -1;

	uint32_t clusterEnt;
	if(dirParentNuevo -> directorio != NULL)
		clusterEnt = proximaEntryDir(dirParentNuevo -> directorio);
	else
		clusterEnt = bootSectorDisco -> BPB_RootClus;

	/*	Antes de crear algo debo verificar que no exista una
	 * 	entrada con el mismo nombre								*/

	ListaDirectorios* firstDir = malloc(sizeof(ListaDirectorios));
	firstDir -> directorio = NULL;
	firstDir -> siguiente = NULL;
	firstDir -> clusters = NULL;
	firstDir -> nombreLargo = NULL;
	ListaDirectorios* lastDir = NULL;
	leerFAT32DirectoryEntries( bootSectorDisco, clusterEnt, firstDir, lastDir);

	if(verificarNombreDistinto(firstDir, nombreArchivoNuevo) == -1)
		/*	hay un archivo con el mismo nombre	*/
		return -1;

	/*	Creo las nuevas entradas con nombres cambiado	*/
	struct DirStruct* dir = malloc(sizeof(struct DirStruct));
	struct LongDirStruct* lfn = malloc(sizeof(struct LongDirStruct));

	if((dirOriginal -> directorio -> DIR_Attr & ATTR_ARCHIVE)== ATTR_ARCHIVE)
		{
		if( crearEntradaDIR(bootSectorDisco, nombreArchivoNuevo, dir, ARCHIVO) == -1)
			return -1;
		}
	else
		if( crearEntradaDIR(bootSectorDisco, nombreArchivoNuevo, dir, DIRECTORIO) == -1)
			return -1;

	if (crearEntradaLFN(nombreArchivoNuevo, dir, lfn) == -1)
		return -1;

	/*	paso el nombre	8.3	*/
	int32_t i = 0;
	for(i=0; i<11; i++)
		dirOriginal -> directorio -> DIR_Name[i] = dir -> DIR_Name[i];

	/*	estoy en el mismo directorio parent	*/
	if(dirOriginal -> parentCluster == clusterEnt)
		modificarDir(bootSectorDisco, dirOriginal, lfn);

	else
		{
		/*	lo tengo que mover de parent cluster	*/
		/*	lo elimino del parent cluster actual	*/
		borrarEntradaCluster(bootSectorDisco, dirOriginal);

		/*	moverlo como una entrada nueva	*/

		dirOriginal -> parentCluster = clusterEnt;
		if((dirOriginal -> directorio -> DIR_Attr & ATTR_DIRECTORY) == ATTR_DIRECTORY)
			{
			/*	el cambio de parent para carpeta es un poco mas complicado	*/
			/*	modificar entrada ..	*/
			modificarDOTDOTDir(bootSectorDisco, proximaEntryDir(dirOriginal-> directorio), clusterEnt);

			}

		if(crearEntradaCluster(bootSectorDisco, clusterEnt, dirOriginal -> directorio, lfn) == -1)
			{
			/*	log, no se pudo crear archivo, espacio lleno	*/
			/*	cambiar entrada de la fat	*/
			return -1;
			}
		}

	// again a la cache
	if((dirOriginal ->directorio ->DIR_Attr & ATTR_ARCHIVE)== ATTR_ARCHIVE)
		renameCacheFile(path, newpath, dirOriginal);

	free(pathAux);
	free(pathSinArchivo);

	return 0;

}

//	log de numeros
/* itoa:  convert n to characters in s */
void itoaFunc(int32_t n, char s[])
{
	 int32_t i, sign;

     if ((sign = n) < 0)  /* record sign */
         n = -n;          /* make n positive */
     i = 0;
     do {       /* generate digits in reverse order */
         s[i++] = n % 10 + '0';   /* get next digit */
     } while ((n /= 10) > 0);     /* delete it */
     if (sign < 0)
         s[i++] = '-';
     s[i] = '\0';
     reverseFunc(s);
}

/* reverse:  reverse string s in place */
 void reverseFunc(char s[])
{
     int32_t i, j;
     char c;

     for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
         c = s[i];
         s[i] = s[j];
         s[j] = c;
     }
}
